package io.itit.ecp.admin.provide.action.controller.miniprogram;

import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import icu.mhb.mybatisplus.plugln.extend.Joins;
import io.itit.ecp.admin.common.enums.CarbonQuotaInputTypeEnums;
import io.itit.ecp.admin.common.enums.IMeterDeviceEnums;
import io.itit.ecp.admin.common.enums.MeterDeviceStaticsTypeEnums;
import io.itit.ecp.admin.provide.action.resp.CarbonCCERStaticsResp;
import io.itit.ecp.admin.provide.action.resp.CarbonQuotaStaticsResp;
import io.itit.ecp.admin.provide.action.resp.EmissionIntensityDataResp;
import io.itit.ecp.admin.provide.action.resp.largescreen.DataOverviewResp;
import io.itit.ecp.admin.provide.action.resp.largescreen.DeviceInfoResp;
import io.itit.ecp.admin.provide.action.resp.miniprogram.IndicatorDataResp;
import io.itit.ecp.admin.server.entity.*;
import io.itit.ecp.admin.server.entity.extend.EnergyDataExtEntity;
import io.itit.ecp.admin.server.service.*;
import io.itit.grass.common.provide.action.resp.ResultResp;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.time.temporal.TemporalAdjusters;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 小程序首页数据
 */
@Api(tags = "小程序首页数据")
@RestController
@RequestMapping("/mini/index")
public class MiniIndexController {

    @Resource
    private IDeviceService deviceService;

    @Resource
    private IMeterDeviceService meterDeviceService;

    @Resource
    private IEnergyDataService energyDataService;

    @Resource
    private ICarbonSinkDataService carbonSinkDataService;

    @Resource
    private ISceneProjectService sceneProjectService;

    @Resource
    private ICarbonQuotaService carbonQuotaService;

    @Resource
    private ICarbonCCERService carbonCCERService;

    @ApiOperation("总览数据")
    @GetMapping("overview")
    public ResultResp<List<DataOverviewResp>> dataOverview(@RequestParam(required = false) String sceneProjectId,
                                                           @RequestParam(required = false) String sceneEdificeId,
                                                           @RequestParam(required = false) String sceneFloorId,
                                                           @RequestParam(required = false) String startTime,
                                                           @RequestParam(required = false) String endTime) {
        LocalDateTime start = StringUtils.hasLength(startTime) ? LocalDate.parse(startTime, DateTimeFormatter.ofPattern("yyyy-MM-dd")).atTime(LocalTime.MIN) : null;
        LocalDateTime end = StringUtils.hasLength(endTime) ? LocalDate.parse(endTime, DateTimeFormatter.ofPattern("yyyy-MM-dd")).atTime(LocalTime.MAX) : LocalDateTime.now();
        LocalDateTime preStart = Objects.isNull(start) ? LocalDateTime.now().with(TemporalAdjusters.firstDayOfYear()).minusYears(1) : start.minusYears(1);
        LocalDateTime preEnd = end.minusYears(1);
        List<DataOverviewResp> result = new ArrayList<>();
        BigDecimal t = new BigDecimal("1000");
        BigDecimal total = staticsEnergyDataOverview(sceneProjectId, sceneEdificeId, sceneFloorId, null, null);
        BigDecimal pre = staticsEnergyDataOverview(sceneProjectId, sceneEdificeId, sceneFloorId, preStart, preEnd);
        BigDecimal value = staticsEnergyDataOverview(sceneProjectId, sceneEdificeId, sceneFloorId, start, end);
        String unit = total.compareTo(t) >= 0 || pre.compareTo(t) >= 0 || value.compareTo(t) >= 0 ? "tce" : "kgce";
        if ("tce".equals(unit)) {
            total = total.divide(t, 2, RoundingMode.HALF_UP);
            pre = pre.divide(t, 2, RoundingMode.HALF_UP);
            value = value.divide(t, 2, RoundingMode.HALF_UP);
        }
        result.add(new DataOverviewResp()
                .setName("能源使用总量")
                .setUnit(unit)
                .setTotal(total)
                .setPreValue(pre)
                .setValue(value)); // 能源使用总量

        total = staticsCarbonEmissionOverview(sceneProjectId, sceneEdificeId, sceneFloorId, null, null);
        pre = staticsCarbonEmissionOverview(sceneProjectId, sceneEdificeId, sceneFloorId, preStart, preEnd);
        value = staticsCarbonEmissionOverview(sceneProjectId, sceneEdificeId, sceneFloorId, start, end);
        unit = total.compareTo(t) >= 0 || pre.compareTo(t) >= 0 || value.compareTo(t) >= 0 ? "tCO2" : "kgCO2";
        if ("tCO2".equals(unit)) {
            total = total.divide(t, 2, RoundingMode.HALF_UP);
            pre = pre.divide(t, 2, RoundingMode.HALF_UP);
            value = value.divide(t, 2, RoundingMode.HALF_UP);
        }
        result.add(new DataOverviewResp()  // 碳排放总量
                .setName("碳排放总量")
                .setUnit(unit)
                .setTotal(total)
                .setPreValue(pre)
                .setValue(value));

        total = carbonSinkDataService.computeCarbonReductionTotal(sceneProjectId, sceneEdificeId, sceneFloorId, (LocalDateTime) null, null);
        pre = carbonSinkDataService.computeCarbonReductionTotal(sceneProjectId, sceneEdificeId, sceneFloorId, preStart, preEnd);
        value = carbonSinkDataService.computeCarbonReductionTotal(sceneProjectId, sceneEdificeId, sceneFloorId, start, end);
        unit = total.compareTo(t) >= 0 || pre.compareTo(t) >= 0 || value.compareTo(t) >= 0 ? "tCO2" : "kgCO2";
        if ("tCO2".equals(unit)) {
            total = total.divide(t, 2, RoundingMode.HALF_UP);
            pre = pre.divide(t, 2, RoundingMode.HALF_UP);
            value = value.divide(t, 2, RoundingMode.HALF_UP);
        }
        result.add(new DataOverviewResp()  // 碳汇总量
                .setName("碳汇总量")
                .setUnit(unit)
                .setTotal(total)
                .setPreValue(pre)
                .setValue(value));
        total = staticsReductionOverview(sceneProjectId, sceneEdificeId, sceneFloorId, null, null);
        pre = staticsReductionOverview(sceneProjectId, sceneEdificeId, sceneFloorId, preStart, preEnd);
        value = staticsReductionOverview(sceneProjectId, sceneEdificeId, sceneFloorId, start, end);
        unit = total.compareTo(t) >= 0 || pre.compareTo(t) >= 0 || value.compareTo(t) >= 0 ? "tCO2" : "kgCO2";
        if ("tCO2".equals(unit)) {
            total = total.divide(t, 2, RoundingMode.HALF_UP);
            pre = pre.divide(t, 2, RoundingMode.HALF_UP);
            value = value.divide(t, 2, RoundingMode.HALF_UP);
        }
        result.add(new DataOverviewResp() // 碳减排总量
                .setName("碳减排总量")
                .setUnit(unit)
                .setTotal(total)
                .setPreValue(pre)
                .setValue(value)
                .setEquivalentTreePlanting(total.divide(new BigDecimal("20.2"), RoundingMode.HALF_DOWN).intValue()));
        return ResultResp.success(result);
    }

    /**
     * 园区介绍
     *
     * @param id 项目Id
     */
    @ApiOperation("园区介绍")
    @GetMapping("introduction")
    public ResultResp<Map<String, Object>> introduction(@RequestParam String id) {
        SceneProjectEntity projectEntity = sceneProjectService.getById(id);
        Map<String, Object> resultData = new HashMap<>();
        String textValue = null;
        String proImgs = null;
        String backgroundImg = null;
        if (Objects.nonNull(projectEntity)) {
            textValue = projectEntity.getProRemark();
            backgroundImg = projectEntity.getBackgroundImg();
        }
        resultData.put("textValue", textValue);
        resultData.put("proImgs", proImgs);
        resultData.put("backgroundImg", backgroundImg);
        return ResultResp.success(resultData);
    }

    private BigDecimal staticsCarbonEmissionOverview(String sceneProjectId,
                                                     String sceneEdificeId,
                                                     String sceneFloorId, LocalDateTime startTime, LocalDateTime endTime) {
        BigDecimal data = Joins.of(EnergyDataEntity.class)
                .selectAs(consumer -> consumer
                        .add("SUM(carbon_emission)", "carbonEmission", false)
                )
                .leftJoin(MeterDeviceEntity.class, MeterDeviceEntity::getId, EnergyDataEntity::getMeterDeviceId)
                .notIn(MeterDeviceEntity::getReadMeterType, IMeterDeviceEnums.ReadMeterType.getZeroCarbonList())
                .end()
                .eq(StringUtils.hasLength(sceneProjectId), EnergyDataEntity::getSceneProjectId, sceneProjectId)
                .eq(StringUtils.hasLength(sceneEdificeId), EnergyDataEntity::getSceneEdificeId, sceneEdificeId)
                .eq(StringUtils.hasLength(sceneFloorId), EnergyDataEntity::getSceneFloorId, sceneFloorId)
                .ge(Objects.nonNull(startTime), EnergyDataEntity::getSolidifyDate, startTime)
                .le(Objects.nonNull(endTime), EnergyDataEntity::getSolidifyDate, endTime)
                .joinGetOne(BigDecimal.class);
        return ObjectUtil.defaultIfNull(data, BigDecimal.ZERO).setScale(2, RoundingMode.HALF_DOWN);
    }


    private BigDecimal staticsReductionOverview(String sceneProjectId,
                                                String sceneEdificeId,
                                                String sceneFloorId, LocalDateTime startTime, LocalDateTime endTime) {
        BigDecimal data = Joins.of(EnergyDataEntity.class)
                .selectAs(consumer -> consumer
                        .add("SUM(carbon_emission)", "carbonEmission", false)
                )
                .leftJoin(MeterDeviceEntity.class, MeterDeviceEntity::getId, EnergyDataEntity::getMeterDeviceId)
                .in(MeterDeviceEntity::getReadMeterType, IMeterDeviceEnums.ReadMeterType.getZeroCarbonList())
                .end()
                .eq(StringUtils.hasLength(sceneProjectId), EnergyDataEntity::getSceneProjectId, sceneProjectId)
                .eq(StringUtils.hasLength(sceneEdificeId), EnergyDataEntity::getSceneEdificeId, sceneEdificeId)
                .eq(StringUtils.hasLength(sceneFloorId), EnergyDataEntity::getSceneFloorId, sceneFloorId)
                .ge(Objects.nonNull(startTime), EnergyDataEntity::getSolidifyDate, startTime)
                .le(Objects.nonNull(endTime), EnergyDataEntity::getSolidifyDate, endTime)
                .joinGetOne(BigDecimal.class);
        return ObjectUtil.defaultIfNull(data, BigDecimal.ZERO).setScale(2, RoundingMode.HALF_DOWN);
    }


    private BigDecimal staticsEnergyDataOverview(String sceneProjectId,
                                                 String sceneEdificeId,
                                                 String sceneFloorId, LocalDateTime startTime, LocalDateTime endTime) {
        EnergyDataEntity dataEntity = energyDataService.getOne(new QueryWrapper<EnergyDataEntity>()
                .select("SUM(standard_coal) AS standard_coal")
                .eq(StringUtils.hasLength(sceneProjectId), "scene_project_id", sceneProjectId)
                .eq(StringUtils.hasLength(sceneEdificeId), "scene_edifice_id", sceneEdificeId)
                .eq(StringUtils.hasLength(sceneFloorId), "scene_floor_id", sceneFloorId)
                .ge(Objects.nonNull(startTime), "solidify_date", startTime)
                .le(Objects.nonNull(endTime), "solidify_date", endTime));
        return Objects.isNull(dataEntity) ? BigDecimal.ZERO : ObjectUtil.defaultIfNull(dataEntity.getStandardCoal(), BigDecimal.ZERO)
                .setScale(2, RoundingMode.HALF_DOWN);
    }


    @ApiOperation("设备数据统计")
    @GetMapping("deviceInfo")
    public ResultResp<DeviceInfoResp> deviceInfo(
            @RequestParam(required = false) String sceneProjectId,
            @RequestParam(required = false) String sceneEdificeId,
            @RequestParam(required = false) String sceneFloorId) {
        DeviceInfoResp infoResp = new DeviceInfoResp();
        infoResp.setOnLineDevicesNum(deviceService.countOnline(sceneProjectId, sceneEdificeId, sceneFloorId) +
                meterDeviceService.countOnline(sceneProjectId, sceneEdificeId, sceneFloorId));
        infoResp.setOutLineDevicesNum(deviceService.countOffline(sceneProjectId, sceneEdificeId, sceneFloorId) +
                meterDeviceService.countOffline(sceneProjectId, sceneEdificeId, sceneFloorId));
        infoResp.setDevicesNum(infoResp.getOnLineDevicesNum() + infoResp.getOutLineDevicesNum());
        return ResultResp.success(infoResp);
    }

    /**
     * 指标数据
     */
    @ApiOperation("指标数据")
    @GetMapping("indicatordata")
    public ResultResp<IndicatorDataResp> indicatorData(@RequestParam(required = false) String sceneProjectId,
                                                       @RequestParam(required = false) String sceneEdificeId,
                                                       @RequestParam(required = false) String sceneFloorId,
                                                       @RequestParam(required = false) String startTime,
                                                       @RequestParam(required = false) String endTime) {
        LocalDateTime start = StringUtils.hasLength(startTime) ? LocalDate.parse(startTime, DateTimeFormatter.ofPattern("yyyy-MM-dd")).atTime(LocalTime.MIN) : null;
        LocalDateTime end = StringUtils.hasLength(endTime) ? LocalDate.parse(endTime, DateTimeFormatter.ofPattern("yyyy-MM-dd")).atTime(LocalTime.MAX) : LocalDateTime.now();
        BigDecimal carbonIntensity = getEmissionIntensityData(sceneProjectId, sceneEdificeId, sceneFloorId, start, end);
        BigDecimal powerGeneration = getPowerGeneration(sceneProjectId, sceneEdificeId, sceneFloorId, start, end);
        BigDecimal energyUse = BigDecimal.ZERO; //TODO: （1）数据来源：管理后台-设备运行状态。（2）公式：可调设备柔性度=abs（调控后当前运行功率-标准运行功率） （3）能源使用柔性度：空间场景、时间条件下所有可调设备的柔性度之和
        BigDecimal t = new BigDecimal("1000");
        IndicatorDataResp dataResp = new IndicatorDataResp()
                .setCarbonIntensity(carbonIntensity.compareTo(t) >= 0 ? carbonIntensity.divide(t, 2, RoundingMode.HALF_UP) : carbonIntensity)
                .setCarbonIntensityUnit(carbonIntensity.compareTo(t) >= 0 ? "tCO2/m²" : "kgCO2/m²")
                .setEnergyUse(energyUse.compareTo(t) >= 0 ? energyUse.divide(t, 2, RoundingMode.HALF_UP) : energyUse)
                .setEnergyUseUnit(energyUse.compareTo(t) >= 0 ? "MW" : "kw")
                .setPowerGeneration(powerGeneration.compareTo(t) >= 0 ? powerGeneration.divide(t, 2, RoundingMode.HALF_UP) : powerGeneration)
                .setPowerGenerationUnit(powerGeneration.compareTo(t) >= 0 ? "MWh" : "kwh")
                .setRemainingCarbonAsset(getRemainingCarbonAsset(sceneProjectId, sceneEdificeId, sceneFloorId, start, end));
        return ResultResp.success(dataResp);
    }

    /**
     * 光伏发电自用量:
     * <p>
     * 光伏发电使用量 = 光伏发电量-光伏上网电量
     */
    private BigDecimal getPowerGeneration(String sceneProjectId, String sceneEdificeId, String sceneFloorId, LocalDateTime start, LocalDateTime end) {
        // 光伏发电量
        BigDecimal powerGeneration = ObjectUtil.defaultIfNull(Joins.of(EnergyDataEntity.class)
                .selectAs(builder -> builder.add("SUM(meter_value)", "meterValue", false))
                .eq(StringUtils.hasLength(sceneProjectId), EnergyDataEntity::getSceneProjectId, sceneProjectId)
                .eq(StringUtils.hasLength(sceneEdificeId), EnergyDataEntity::getSceneEdificeId, sceneEdificeId)
                .eq(StringUtils.hasLength(sceneFloorId), EnergyDataEntity::getSceneFloorId, sceneFloorId)
                .eq(EnergyDataEntity::getReadMeterType, IMeterDeviceEnums.ReadMeterType.readMeterType11.getValue())
                .eq(EnergyDataEntity::getStaticsType, MeterDeviceStaticsTypeEnums.POWER_GENERATION.getValue())
                .ge(Objects.nonNull(start), EnergyDataEntity::getSolidifyDate, start)
                .le(Objects.nonNull(end), EnergyDataEntity::getSolidifyDate, end)
                .joinGetOne(BigDecimal.class), BigDecimal.ZERO);
        // 光伏上网电量
        BigDecimal onGrid = ObjectUtil.defaultIfNull(Joins.of(EnergyDataEntity.class)
                .selectAs(builder -> builder.add("SUM(meter_value)", "meterValue", false))
                .eq(StringUtils.hasLength(sceneProjectId), EnergyDataEntity::getSceneProjectId, sceneProjectId)
                .eq(StringUtils.hasLength(sceneEdificeId), EnergyDataEntity::getSceneEdificeId, sceneEdificeId)
                .eq(StringUtils.hasLength(sceneFloorId), EnergyDataEntity::getSceneFloorId, sceneFloorId)
                .eq(EnergyDataEntity::getReadMeterType, IMeterDeviceEnums.ReadMeterType.readMeterType11.getValue())
                .eq(EnergyDataEntity::getStaticsType, MeterDeviceStaticsTypeEnums.ON_GRID_ENERGY.getValue())
                .ge(Objects.nonNull(start), EnergyDataEntity::getSolidifyDate, start)
                .le(Objects.nonNull(end), EnergyDataEntity::getSolidifyDate, end)
                .joinGetOne(BigDecimal.class), BigDecimal.ZERO);
        return powerGeneration.subtract(onGrid).setScale(2, RoundingMode.HALF_DOWN);
    }

    /**
     * 剩余碳资产
     */
    private BigDecimal getRemainingCarbonAsset(String sceneProjectId, String sceneEdificeId, String sceneFloorId, LocalDateTime start, LocalDateTime end) {
        CarbonQuotaStaticsResp staticsCarbonQuota = staticsCarbonQuota(sceneProjectId, sceneEdificeId, sceneFloorId, start, end);
        CarbonCCERStaticsResp staticsCCER = staticsCCER(sceneProjectId, sceneEdificeId, sceneFloorId, start, end);
        return staticsCarbonQuota.getRemainingValue().add(staticsCCER.getRemainingValue());
    }

    private CarbonCCERStaticsResp staticsCCER(String sceneProjectId,
                                              String sceneEdificeId,
                                              String sceneFloorId, LocalDateTime startTime,
                                              LocalDateTime endTime) {
        CarbonCCERStaticsResp staticsResp = new CarbonCCERStaticsResp();
        List<CarbonCCEREntity> carbonCCEREntities = carbonCCERService.list(new LambdaQueryWrapper<CarbonCCEREntity>()
                .eq(StringUtils.hasLength(sceneProjectId), CarbonCCEREntity::getSceneProjectId, sceneProjectId)
                .eq(StringUtils.hasLength(sceneEdificeId), CarbonCCEREntity::getSceneEdificeId, sceneEdificeId)
                .eq(StringUtils.hasLength(sceneFloorId), CarbonCCEREntity::getSceneFloorId, sceneFloorId)
                .ge(Objects.nonNull(startTime), CarbonCCEREntity::getCreateTm, startTime)
                .le(CarbonCCEREntity::getCreateTm, endTime)
        );
        Map<String, List<CarbonCCEREntity>> inputTypeMap = carbonCCEREntities.stream().collect(Collectors.groupingBy(CarbonCCEREntity::getInputType));
        staticsResp.setSaleValue(inputTypeMap.getOrDefault(CarbonQuotaInputTypeEnums.SOLD.getValue(), Collections.emptyList())
                .stream().map(CarbonCCEREntity::getCcerValue).reduce(BigDecimal.ZERO, BigDecimal::add).setScale(2, RoundingMode.HALF_DOWN));
        staticsResp.setPurchasedValue(inputTypeMap.getOrDefault(CarbonQuotaInputTypeEnums.PURCHASE.getValue(), Collections.emptyList())
                .stream().map(CarbonCCEREntity::getCcerValue).reduce(BigDecimal.ZERO, BigDecimal::add).setScale(2, RoundingMode.HALF_DOWN));

        staticsResp.setTotalValue(queryReductionData(sceneProjectId, sceneEdificeId, sceneFloorId, null, startTime, endTime)
                .add(staticsResp.getPurchasedValue()).setScale(2, RoundingMode.HALF_DOWN));
        staticsResp.setRemainingValue(staticsResp.getTotalValue()
                .subtract(staticsResp.getSaleValue()));
        return staticsResp;
    }

    private CarbonQuotaStaticsResp staticsCarbonQuota(String sceneProjectId,
                                                      String sceneEdificeId,
                                                      String sceneFloorId, LocalDateTime startTime,
                                                      LocalDateTime endTime) {
        CarbonQuotaStaticsResp staticsResp = new CarbonQuotaStaticsResp();
        List<CarbonQuotaEntity> quotaEntities = carbonQuotaService.list(new LambdaQueryWrapper<CarbonQuotaEntity>()
                .eq(StringUtils.hasLength(sceneProjectId), CarbonQuotaEntity::getSceneProjectId, sceneProjectId)
                .eq(StringUtils.hasLength(sceneEdificeId), CarbonQuotaEntity::getSceneEdificeId, sceneEdificeId)
                .eq(StringUtils.hasLength(sceneFloorId), CarbonQuotaEntity::getSceneFloorId, sceneFloorId)
                .ge(Objects.nonNull(startTime), CarbonQuotaEntity::getCreateTm, startTime)
                .le(CarbonQuotaEntity::getCreateTm, endTime)
        );
        Map<String, List<CarbonQuotaEntity>> inputTypeMap = quotaEntities.stream().collect(Collectors.groupingBy(CarbonQuotaEntity::getInputType));
        BigDecimal totalValue = inputTypeMap.getOrDefault(CarbonQuotaInputTypeEnums.ADD.getValue(), Collections.emptyList())
                .stream().map(CarbonQuotaEntity::getQuotaValue).reduce(BigDecimal.ZERO, BigDecimal::add);
        staticsResp.setTotalValue(totalValue);
        staticsResp.setSaleValue(inputTypeMap.getOrDefault(CarbonQuotaInputTypeEnums.SOLD.getValue(), Collections.emptyList())
                .stream().map(CarbonQuotaEntity::getQuotaValue).reduce(BigDecimal.ZERO, BigDecimal::add));
        staticsResp.setPurchasedValue(inputTypeMap.getOrDefault(CarbonQuotaInputTypeEnums.PURCHASE.getValue(), Collections.emptyList())
                .stream().map(CarbonQuotaEntity::getQuotaValue).reduce(BigDecimal.ZERO, BigDecimal::add));

        staticsResp.setUseValue(getUsedValue(sceneProjectId, sceneEdificeId,
                sceneFloorId, startTime, endTime));

        staticsResp.setRemainingValue(staticsResp.getTotalValue()
                .subtract(staticsResp.getUseValue())
                .add(staticsResp.getPurchasedValue())
                .subtract(staticsResp.getSaleValue()));
        return staticsResp;
    }

    private BigDecimal queryReductionData(String sceneProjectId,
                                          String sceneEdificeId,
                                          String sceneFloorId,
                                          String sceneRoomId,
                                          LocalDateTime startTime, LocalDateTime endTime) {
        BigDecimal data = Joins.of(EnergyDataEntity.class)
                .selectAs(consumer -> consumer
                        .add("SUM(carbon_emission)", "carbonEmission", false)
                )
                .leftJoin(MeterDeviceEntity.class, MeterDeviceEntity::getId, EnergyDataEntity::getMeterDeviceId)
                .in(MeterDeviceEntity::getReadMeterType, IMeterDeviceEnums.ReadMeterType.getZeroCarbonList())
                .end()
                .eq(StringUtils.hasLength(sceneProjectId), EnergyDataEntity::getSceneProjectId, sceneProjectId)
                .eq(StringUtils.hasLength(sceneEdificeId), EnergyDataEntity::getSceneEdificeId, sceneEdificeId)
                .eq(StringUtils.hasLength(sceneFloorId), EnergyDataEntity::getSceneFloorId, sceneFloorId)
                .eq(StringUtils.hasLength(sceneRoomId), EnergyDataEntity::getSceneRoomId, sceneRoomId)
                .ge(Objects.nonNull(startTime), EnergyDataEntity::getSolidifyDate, startTime)
                .le(Objects.nonNull(endTime), EnergyDataEntity::getSolidifyDate, endTime)
                .joinGetOne(BigDecimal.class);
        return ObjectUtil.defaultIfNull(data, BigDecimal.ZERO);
    }


    private BigDecimal getUsedValue(String sceneProjectId, String sceneEdificeId, String sceneFloorId, LocalDateTime start, LocalDateTime end) {
        BigDecimal res = Joins.of(EnergyDataEntity.class)
                .selectAs(builder -> builder
                        .add("SUM(carbon_emission)", "carbonEmission", false)
                )
                .leftJoin(MeterDeviceEntity.class, MeterDeviceEntity::getId, EnergyDataEntity::getMeterDeviceId)
                .notIn(MeterDeviceEntity::getReadMeterType, IMeterDeviceEnums.ReadMeterType.getZeroCarbonList())
                .end()
                .eq(StringUtils.hasLength(sceneProjectId), EnergyDataEntity::getSceneProjectId, sceneProjectId)
                .eq(StringUtils.hasLength(sceneEdificeId), EnergyDataEntity::getEnergyTypeId, sceneEdificeId)
                .eq(StringUtils.hasLength(sceneFloorId), EnergyDataEntity::getSceneEdificeId, sceneFloorId)
                .ge(Objects.nonNull(start), EnergyDataEntity::getSolidifyDate, start)
                .le(Objects.nonNull(end), EnergyDataEntity::getSolidifyDate, end)
                .joinGetOne(BigDecimal.class);
        return Objects.isNull(res) ? BigDecimal.ZERO : res.setScale(2, RoundingMode.HALF_UP);
    }


    private BigDecimal getEmissionIntensityData(String sceneProjectId, String sceneEdificeId, String sceneFloorId, LocalDateTime start, LocalDateTime end) {
        List<EmissionIntensityDataResp> list = Joins.of(EnergyDataEntity.class)
                .select(EnergyDataEntity::getCarbonEmission)
                .leftJoin(MeterDeviceEntity.class, MeterDeviceEntity::getId, EnergyDataEntity::getMeterDeviceId)
                .selectAs(t -> t.addFunAlias(MeterDeviceEntity::getDeviceCode, EnergyDataExtEntity::getDeviceCode)
                        .addFunAlias(MeterDeviceEntity::getDeviceName, EnergyDataExtEntity::getDeviceName)
                        .addFunAlias(MeterDeviceEntity::getReadMeterType, EnergyDataExtEntity::getReadMeterType)
                        .addFunAlias(MeterDeviceEntity::getReadMeterTag, EnergyDataExtEntity::getReadMeterTag)
                )
                .in(MeterDeviceEntity::getReadMeterType, IMeterDeviceEnums.ReadMeterType.getZeroCarbonList())
                .end()
                .leftJoin(SceneProjectEntity.class, SceneProjectEntity::getId, EnergyDataEntity::getSceneProjectId)
                .select(SceneProjectEntity::getProjectName)
                .end()
                .leftJoin(SceneRoomEntity.class, SceneRoomEntity::getId, EnergyDataEntity::getSceneRoomId)
                .selectAs(SceneRoomEntity::getRoomArea, EmissionIntensityDataResp::getArea)
                .end()
                .eq(org.apache.commons.lang3.StringUtils.isNotEmpty(sceneProjectId), EnergyDataEntity::getSceneProjectId, sceneProjectId)
                .eq(org.apache.commons.lang3.StringUtils.isNotEmpty(sceneEdificeId), EnergyDataEntity::getSceneEdificeId, sceneEdificeId)
                .eq(org.apache.commons.lang3.StringUtils.isNotEmpty(sceneFloorId), EnergyDataEntity::getSceneFloorId, sceneFloorId)
                .ge(Objects.nonNull(start), EnergyDataEntity::getSolidifyDate, start)
                .le(Objects.nonNull(end), EnergyDataEntity::getSolidifyDate, end).joinList(EmissionIntensityDataResp.class);

        return list.stream()
                .map(item -> item.getCarbonEmission().multiply(ObjectUtil.defaultIfNull(item.getArea(), BigDecimal.ZERO)))
                .reduce(BigDecimal.ZERO, BigDecimal::add).setScale(2, RoundingMode.HALF_DOWN);
    }
}
